home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Tools & Apps / Graphics & Imaging / Virtual Sphere 1.0 / SampleAdditional.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-14  |  14.6 KB  |  422 lines  |  [TEXT/MPS ]

  1. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  2. /* SampleAdditional.c
  3. /*
  4. /* This file contains routines to replace the standard ones in Sample.c
  5. /*
  6. /* Author: Michael Chen, Human Interface Group / ATG
  7. /* Copyright © 1991-1992 Apple Computer, Inc.  All rights reserved.
  8. /*
  9. /* Part of Virtual Sphere Sample Code Release v1.0
  10. /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
  11.  
  12. #ifndef    __SAMPLEADDITIONAL__
  13. #include "SampleAdditional.h"
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef __FIXMATH__
  21. #include <FixMath.h>
  22. #endif
  23.  
  24. #ifndef __ERRORS__
  25. #include <Errors.h>
  26. #endif
  27.  
  28. #ifndef __GRAF3D__
  29. #include <Graf3D.h>
  30. #endif
  31.  
  32. #ifndef __MENUS__
  33. #include <Menus.h>
  34. #endif
  35.  
  36. #ifndef __OFFSCREEN__
  37. #include "Offscreen.h"
  38. #endif
  39.  
  40. #ifndef __MyMath__
  41. #include "MyMath.h"
  42. #endif
  43.  
  44. #ifndef    __GRAPHICS3D__
  45. #include "Graphics3D.h"
  46. #endif
  47.  
  48. #ifndef    __VIRTUALSPHERE__
  49. #include "VirtualSphere.h"
  50. #endif
  51.  
  52. #include "Sample.h"
  53.  
  54. #define    Long2Fix(x)            (Fixed)(x<<16)                    /* override standard trap call */
  55. #include "ObjectData.h"
  56.  
  57. /* Define values for the Virtual Sphere cue circle.
  58.  * In a real application, the cue circle should resize to the currently selected object */ 
  59. #define    kSphereCenterH    150
  60. #define    kSphereCenterV    150
  61. #define    kSphereRadius    130
  62.  
  63. /* Routine global to this file (module) only */
  64. static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D    objectMatrix);
  65.  
  66. /* Variables global to this file (module) only */
  67. static Port3DPtr    lgThePort3DPtr;                /* global pointer used to remember the current Port3D */
  68. static Port3D        lgMyPort3D;
  69. static Matrix4D        lgObjectMatrix;
  70. static GWorldPtr    lgOffscreenGWorld = nil;
  71.  
  72. /*=================================================================================================
  73. /* Initialize3D
  74. /*
  75. /* Set up Graf3D, create an offscreen buffer for the window and display parameters.
  76. /*-------------------------------------------------------------------------------------------------*/
  77. void Initialize3D (WindowPtr window)
  78. {
  79.     Rect        globalRect;
  80.     Boolean        gWorldAvailable;
  81.     
  82.     /* Setup offscreen buffer */
  83.     if (InitializeOffscreen (&gWorldAvailable) != noErr) {
  84.         MessageAlertAndQuit ("\pInitOffscreen returned an error.");
  85.     }
  86.     if (!gWorldAvailable) {
  87.         MessageAlertAndQuit ("\pThis application requires 32-bit Color Quickdraw or System 7.");
  88.     }
  89.         
  90.     if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) != noErr) {
  91.         /* Note CheckOffscreenForWindow() has already set lgOffscreenGWorld to nil. */
  92.         MessageAlert ("\pThere is not enough memory to do double buffering.");
  93.         gDoubleBuffer = false;
  94.     } else {
  95.         gDoubleBuffer = true;
  96.     }
  97.  
  98.     /* Initialize our 3D graphics rountines */
  99.     if (InitializeGraphics3D() != noErr) {
  100.         MessageAlertAndQuit ("\pInitialzeGraphics3D.");
  101.     }
  102.     
  103.     /* Initialize Graf3D */
  104.     InitGrf3d (&lgThePort3DPtr);    /* Must call */
  105.     SetPort (window);            /* to make sure OpenPort3D uses the current GrafPort */
  106.     Open3DPort (&lgMyPort3D);    /* Open3DPort fills in the lgMyPort3D record with 
  107.                                  * appropriate values (including setting the field
  108.                                  * lgMyPort3D.grPort to the current GrafPort */
  109.     SetPort3D (&lgMyPort3D);        /* Make sure we are using this Port3D */
  110.  
  111.     /* Make the 3D viewport the same size as the window */
  112.     ViewPort (&(lgMyPort3D.grPort->portRect));
  113.     
  114.     /* Set up the 3D viewing pyrimid.  Note the top and bottom parameters are flipped so
  115.      * that y increases going up */
  116.     #define kXMin        -200
  117.     #define kXMax         200
  118.     #define kYMin        -200
  119.     #define kYMax         200
  120.     LookAt (Long2Fix(kXMin), Long2Fix(kYMax), Long2Fix(kXMax), Long2Fix(kYMin));
  121.     ViewAngle (Long2Fix (25));
  122.     
  123.     /* Unset the optimization flag within Graf3D which "remembers" if lgMyPort3D.xForm is
  124.      * identity or not. This is needed since we modify lgMyPort3D.xForm directly via the
  125.      * Matrix2XfMatrix() call below.  We never call any of the Graf3D routines which
  126.      * indirectly modify the xForm matrix. */
  127.      Scale (Long2Fix (1), Long2Fix (1), Long2Fix (1));    /* Actually any Graf3D transform call
  128.                                                           * that generates a indentity matrix
  129.                                                           * will do */
  130.  
  131.     /* Initialize the object matrix to identity.  Note the object matrix is in floating point.
  132.      * This matrix is then converted and stored into Graf3D's xForm matrix (in Fixed point format). */
  133.     lgObjectMatrix [0][0] = lgObjectMatrix [1][1] = lgObjectMatrix [2][2] = lgObjectMatrix [3][3] = 1;
  134.     lgObjectMatrix [0][1] = lgObjectMatrix [0][2] = lgObjectMatrix [0][3] = 
  135.     lgObjectMatrix [1][0] = lgObjectMatrix [1][2] = lgObjectMatrix [1][3] = 
  136.     lgObjectMatrix [2][0] = lgObjectMatrix [2][1] = lgObjectMatrix [2][3] = 
  137.     lgObjectMatrix [3][0] = lgObjectMatrix [3][1] = lgObjectMatrix [3][2] = 0;
  138.     Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
  139.  
  140.     /* Setup default drawing styles for the 3D object. */
  141.     gObjectDisplayed = iHouse;
  142.     gRenderingStyle = iFlatShading;            
  143.     gDoBackfacedPolygonRemoval = true;
  144.     globalRect = window->portRect;
  145.     LocalToGlobalRect (&globalRect);
  146.     gDrawInColor = gMac.hasColorQD && (ScreenDepth (&globalRect) > 1);
  147. }
  148.  
  149. /*=================================================================================================
  150. /* CleanUp3D
  151. /*
  152. /* Clean up 3D stuff before quiting application.
  153. /*-------------------------------------------------------------------------------------------------*/
  154. void CleanUp3D ()
  155. {
  156.     FreeOffscreen (lgOffscreenGWorld);
  157.     FreeGraphics3D ();
  158. }
  159.  
  160. /*=================================================================================================
  161. /* AdjustAdditionalMenus
  162. /*
  163. /* Enable / disable menus items related to this 3D sample program
  164. /*-------------------------------------------------------------------------------------------------*/
  165. void AdjustAdditionalMenus ()
  166. {
  167.     Boolean        isAppWindow;
  168.     MenuHandle    menu;
  169.     
  170.     isAppWindow = !IsDAWindow (FrontWindow());
  171.  
  172.     menu = GetMHandle (mObject);
  173.     EnableDisableItem (menu, iCube,                    isAppWindow);
  174.     EnableDisableItem (menu, iIcosahedron,             isAppWindow);
  175.     EnableDisableItem (menu, iHouse,                   isAppWindow);
  176.     CheckItem         (menu, iCube,                    gObjectDisplayed == iCube);
  177.     CheckItem         (menu, iIcosahedron,             gObjectDisplayed == iIcosahedron);
  178.     CheckItem         (menu, iHouse,                   gObjectDisplayed == iHouse);
  179.  
  180.     menu = GetMHandle (mOptions);
  181.     EnableDisableItem (menu, iLineDrawing,             isAppWindow);
  182.     EnableDisableItem (menu, iFlatShading,             isAppWindow);
  183.     EnableDisableItem (menu, iFlatShadingWithOutline,  isAppWindow);
  184.     EnableDisableItem (menu, iDrawInBW,                   isAppWindow);
  185.     EnableDisableItem (menu, iDrawInColor,             isAppWindow && gMac.hasColorQD);
  186.     EnableDisableItem (menu, iBackfacedPolygonRemoval, isAppWindow);
  187.     EnableDisableItem (menu, iDoubleBuffer,            isAppWindow && (lgOffscreenGWorld != nil));
  188.     CheckItem         (menu, iLineDrawing,             gRenderingStyle == iLineDrawing);
  189.     CheckItem         (menu, iFlatShading,             gRenderingStyle == iFlatShading);
  190.     CheckItem         (menu, iFlatShadingWithOutline,  gRenderingStyle == iFlatShadingWithOutline);
  191.     CheckItem         (menu, iDrawInBW,                   !gDrawInColor);
  192.     CheckItem         (menu, iDrawInColor,               gDrawInColor);
  193.     CheckItem         (menu, iBackfacedPolygonRemoval, gDoBackfacedPolygonRemoval);
  194.     CheckItem         (menu, iDoubleBuffer,            gDoubleBuffer);
  195. }
  196.  
  197. /*=================================================================================================
  198. /* CheckSystemConfiguration
  199. /*
  200. /* If system configuration is not right, alert user and exit to Finder.
  201. /* Must be universal code
  202. /*-------------------------------------------------------------------------------------------------*/
  203. #ifdef applec
  204. #pragma push
  205. #pragma processor 68000
  206. #endif
  207. void CheckSystemConfiguration ()
  208. {
  209.     #ifdef THINK_C
  210.     #pragma options(!mc68020)
  211.     #endif
  212.  
  213.     if (qUseFPUand020 && !(gMac.hasFPU)) {
  214.         /* Should use string resource to show this message! */
  215.         MessageAlertAndQuit ("\pSorry.  You can only run this application on a Mac with a '020 processor and math coprocessor.");
  216.     }
  217. }
  218. #ifdef applec
  219. #pragma pop
  220. #endif
  221.  
  222. /*=================================================================================================
  223. /* DoAdditionalMenuCommand
  224. /*
  225. /* Deal with menus selections related to this 3D sample program
  226. /*-------------------------------------------------------------------------------------------------*/
  227. void DoAdditionalMenuCommand (long menuResult)
  228. {
  229.     short        menuID;                /* the resource ID of the selected menu */
  230.     short        menuItem;            /* the item number of the selected menu */
  231.     WindowPtr    window;
  232.  
  233.     menuID = HiWord (menuResult);    /* use macros for efficiency to... */
  234.     menuItem = LoWord (menuResult);    /* get menu item number and menu number */
  235.     window = FrontWindow ();
  236.  
  237.     switch (menuID) {
  238.         case mObject:
  239.             switch (menuItem) {
  240.                 case iCube:
  241.                     gObjectDisplayed = iCube;
  242.                     break;
  243.                 case iIcosahedron:
  244.                     gObjectDisplayed = iIcosahedron;
  245.                     break;
  246.                 case iHouse:
  247.                     gObjectDisplayed = iHouse;
  248.                     break;
  249.             }
  250.             InvalRect (&window->portRect);
  251.             break;
  252.         case mOptions:
  253.             switch (menuItem) {
  254.                 case iLineDrawing:
  255.                     gRenderingStyle = iLineDrawing;            
  256.                     break;
  257.                 case iFlatShading:
  258.                     gRenderingStyle = iFlatShading;            
  259.                     break;
  260.                 case iFlatShadingWithOutline:
  261.                     gRenderingStyle = iFlatShadingWithOutline;            
  262.                     break;
  263.                 case iBackfacedPolygonRemoval:
  264.                     gDoBackfacedPolygonRemoval = !gDoBackfacedPolygonRemoval;
  265.                     break;
  266.                 case iDoubleBuffer:
  267.                     gDoubleBuffer = !gDoubleBuffer;
  268.                     break;
  269.                 case iDrawInBW:
  270.                     gDrawInColor = false;
  271.                     break;
  272.                 case iDrawInColor:
  273.                     gDrawInColor = true;
  274.                     break;
  275.             }
  276.             InvalRect (&window->portRect);
  277.             break;
  278.     }
  279. }
  280.  
  281. /*=================================================================================================
  282. /* DoContentClick
  283. /*
  284. /* Called when there is a mouse down in the window content.
  285. /* In this sample app, we only need to rotate the displayed object.  In a more
  286. /* complex app, you would  probably need to determine which object is clicked and
  287. /* figure out what operation you should apply to that object.
  288. /*-------------------------------------------------------------------------------------------------*/
  289. void DoContentClick (WindowPtr window, EventRecord *event)
  290. {
  291.     DoRotation (window,    event, lgObjectMatrix);
  292. }
  293.  
  294. /*=================================================================================================
  295. /* DoRotation
  296. /*
  297. /* Called when there is a mouse down in the window content.
  298. /* Use the Virtual Sphere to rotate the current object on the screen.
  299. /* In a 3D graphics program, an objects usually has associated with it a "modeling" matrix.
  300. /* An object is rotated by modifying its modeling matrix.  This is done here by repeatedly
  301. /* concatenating the rotation determined by the Virtual Sphere to the object's matrix while
  302. /* the user is dragging the mouse.
  303. /*-------------------------------------------------------------------------------------------------*/
  304. static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D    objectMatrix)
  305. {
  306.     Point        p0, p1;
  307.     short        dx, dy;
  308.     Point        sphereCenter; 
  309.     Real        sphereRadius; 
  310.     CPoint3D    axisOfRotation;
  311.     Real        angleOfRotation;
  312.     Matrix4D    tempMatrix;
  313.     Matrix4D    rotationMatrix;
  314.     
  315.     SetCursor (*GetCursor(crossCursor));
  316.     
  317.     /* Get the mouse down point */
  318.     p1 = event->where;
  319.     GlobalToLocal (&p1);
  320.     
  321.     /* Figure out where to place the Virtual Sphere cue circle.
  322.      * In this sample app., the cue is always centered on the window with a fixed size.
  323.      * In an general app., you will need to determine the location and size of cue
  324.      * (in screen coordinates) to surround the object */
  325.     sphereCenter.h = kSphereCenterH; 
  326.     sphereCenter.v = kSphereCenterV; 
  327.     sphereRadius   = kSphereRadius;
  328.     
  329.     while (StillDown()) {                                
  330.         GetMouse (&p0);
  331.         dx = p0.h - p1.h;
  332.         dy = p0.v - p1.v;
  333.         if (dx != 0 || dy != 0) {
  334.             /* Determine the amount of rotation from the mouse movement */
  335.             VirtualSphere (p0, p1, sphereCenter, sphereRadius, &axisOfRotation, &angleOfRotation);
  336.             /* Compute the corresponding rotation matrix */
  337.             SetRotationMatrix (rotationMatrix, &axisOfRotation, angleOfRotation);
  338.             
  339.             /* Concatenate the new rotation with the current rotation */
  340.             MultiplyMatrix (objectMatrix, rotationMatrix, tempMatrix);
  341.             CopyMatrix (tempMatrix, objectMatrix);
  342.             
  343.             /* The next routine may be called if the objectMatrix really gets "out of shape"
  344.              * due to numeric inaccuracies from repeated matrix multiplications.  This does not
  345.              * happen in this demo program so the call is commented out */
  346.             /* OrthogonalizeRotationMatrix (objectMatrix); */
  347.             
  348.             /* Update the window */
  349.             DrawWindow (window);
  350.             
  351.             p1 = p0;        /* remember the current mouse location for the next iteration */
  352.         }
  353.     }
  354. }
  355.  
  356. /*=================================================================================================
  357. /* DrawWindow
  358. /*
  359. /* Draw the current 3D object and surround it with the Virtual Sphere cue.  In this sample
  360. /* application, the object is always centered on the window with a fixed size.
  361. /* In an general app., you will need to determine the location and size of sphere
  362. /* to surround the object.
  363. /*-------------------------------------------------------------------------------------------------*/
  364. void DrawWindow (WindowPtr window)
  365. {
  366.     Rect sphereRect;
  367.     
  368.     SetPort3D (&lgMyPort3D);
  369.     /* Convert and store our matrix into the Graf3D matrix */
  370.     Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
  371.  
  372.     if (gDoubleBuffer) BeginDrawingOffscreen (lgOffscreenGWorld, window);
  373.  
  374.     EraseRect (&qd.thePort->portRect);
  375.  
  376.     /* Draw the object */
  377.     switch (gObjectDisplayed) {
  378.         case iCube:
  379.             DrawPolyNet (&gCubeData);
  380.             break;
  381.         case iIcosahedron:
  382.             DrawPolyNet (&gIcosahedronData);
  383.             break;
  384.         case iHouse:
  385.             DrawPolyNet (&gHouseData);
  386.             break;
  387.     }
  388.  
  389.     /* Draw Virtual Sphere cue around the object */
  390.     SetRect (&sphereRect, kSphereCenterH-kSphereRadius, kSphereCenterV-kSphereRadius,
  391.                           kSphereCenterH+kSphereRadius, kSphereCenterV+kSphereRadius); 
  392.     ForeColor (magentaColor);
  393.     FrameOval (&sphereRect);
  394.  
  395.     if (gDoubleBuffer) EndDrawingOffscreen (lgOffscreenGWorld, window);
  396. }
  397.  
  398. /*=================================================================================================
  399. /* UpdateWindow
  400. /*
  401. /* Deal with update event.  Reallocate the offscreen buffer if the window has been moved
  402. /* or the bit-depth has been changed.  Then draw the window content if needed.
  403. /*-------------------------------------------------------------------------------------------------*/
  404. void UpdateWindow (WindowPtr window)
  405. {
  406.     if (gDoubleBuffer) {
  407.         if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) == memFullErr) {
  408.             MessageAlert ("\pThere is not enough memory to do double buffering for this screen depth.");
  409.             if (lgOffscreenGWorld == nil) gDoubleBuffer = false;
  410.         }
  411.     }
  412.  
  413.     BeginUpdate (window);
  414.     
  415.     if (!EmptyRgn (window->visRgn)) {
  416.         /* Updating needs to be done */
  417.         DrawWindow (window);
  418.     }    
  419.  
  420.     EndUpdate (window);
  421. }
  422.